package jmine.tec.hydra.domain.actions;

import java.util.Collections;
import java.util.List;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

import jmine.tec.hydra.HydraMessages;
import jmine.tec.hydra.api.CallActivationAction;
import jmine.tec.hydra.api.EncodeMessageAction;
import jmine.tec.hydra.api.HydraAction;
import jmine.tec.hydra.api.HydraSpecification;
import jmine.tec.hydra.domain.HydraActivation;
import jmine.tec.hydra.exception.HydraException;
import jmine.tec.persist.annotation.DiscriminatorComment;

import org.apache.commons.lang.StringUtils;

import bancosys.tec.persist.dao.BaseDAO;
import bancosys.tec.persist.dao.BeanNotFoundException;

/**
 * Ação que invoca o script de ativação para uma chamada via api e decide que especificações devem ser executadas
 * 
 * @author lundberg
 */
@Entity
@DiscriminatorValue("4")
@DiscriminatorComment("ATIVACAO VIA API")
public class DefaultCallActivationAction extends AbstractHydraAction implements CallActivationAction {

    // Atributos transientes, existem apenas na criação da action e deixam de existir uma vez que a mensagem foi armazenada com sucesso.
    private Object source;

    private String mnemonicoActivation;

    /**
     * {@inheritDoc}
     */
    public CallActivationAction prepare(Object src, String mneActivation) {
        this.source = src;
        this.mnemonicoActivation = mneActivation;
        return this;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected List<HydraAction> doExecute() throws Exception {
        HydraActivation activation = this.findActivation();
        this.setSystem(activation.getSystem());
        LOGGER.debug(String.format("Encontrou ativação para %s.", this.mnemonicoActivation));
        String action = activation.executeSend(this.source);
        LOGGER.debug(String.format("Activation executado com sucesso, resultando na action '%s'.", action));
        if (StringUtils.isEmpty(action)) {
            this.logAsSystem(String.format("Não encontrou ação na ativação de %s para o objeto %s.", activation.getMnemonico(), this.source));
            this.markAsPending();
            return Collections.emptyList();
        } else {
            HydraSpecification specification = this.findSpecification(activation, action);
            this.setSpecification(specification);
            if (specification.isEnabled()) {
                EncodeMessageAction encode = this.getController().getProvider().createAction(EncodeMessageAction.class);
                encode.prepare(this.source);
                return Collections.<HydraAction> singletonList(encode);
            } else {
                this.logAsSystem("Especificação desabilitada. Sistema: " + specification.getSystem().getMnemonico());
                return Collections.emptyList();
            }
        }
    }

    /**
     * Busca a especificação
     * 
     * @param activation activation
     * @param action action
     * @return HydraSpecification
     */
    private HydraSpecification findSpecification(HydraActivation activation, String action) {
        try {
            return this.getController().getProvider().findSpecification(activation.getSystem(), action);
        } catch (BeanNotFoundException e) {
            throw new HydraException(HydraMessages.SEND_NO_SPECIFICATION_FOUND.create(action), e);
        }
    }

    /**
     * @return ativação encontrada a partir de seu mnemonico.
     */
    private HydraActivation findActivation() {
        try {
            BaseDAO<HydraActivation> activationDAO = this.getController().getDAOFactory().getGenericDAO(HydraActivation.class);
            return activationDAO.findByNaturalKey(this.mnemonicoActivation);
        } catch (BeanNotFoundException e) {
            throw new HydraException(HydraMessages.SEND_NO_ACTIVATION_FOUND.create(this.mnemonicoActivation), e);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected String createDescription() {
        return "Ativação para envio de mensagem";
    }
}
